package br.unisul.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Classe responsavel pela leitura do arquivo e transformar em um vetor de double
 * <h3>Exemplo:</h3>
 * <h4>Conteudo do arquivo representando a letra <i>C</i>:</h4>
 * ###<br>
 * #.?<br>
 * #..<br>
 * #..<br>
 * ###<br>
 * <h4>Map Configuração:</h4>
 * <table>
 * <tr ALIGN="center"> 
 * <td>Character<td>Double
 * <tr ALIGN="center"> 
 * <td>.<td>-1.0
 * <tr ALIGN="center"> 
 * <td>#<td>1.0
 * </td></td>
 * </table>
 * valorDesconhecido = 0
 * <h4>Aplicando o metodo: toArray(int linhas, int colunas)</h4>
 * toArray(5, 3) //No arquivo podemos notar que possui 5 linhas com colunas de 3 Character
 * <br>
 * Resultado: [1.0, 1.0, 1.0, 1.0, -1.0, 0.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0]
 * <br>
 * <br>
 * @author Joelson Fernandes
 *
 */
public class LeituraArquivo {

	/**
	 * Arquivo a ser lido
	 */
	private File file;

	private Map<Character, Double> configuracoes;

	private double valorDesconhecido;


	/**
	 * Inicia um {@link LeituraArquivo} vazio
	 */
	public LeituraArquivo() {
		this(null);
	}

	/**
	 * Constroi um leitor de arquivo, onde ele ira abri o arquivo
	 * e podera transformar em um vetor de double, sendo que
	 * cada {@link Character} do arquivo irá conter um valor desta forma:<p>
	 * <table> Configurações:
	 * <tr ALIGN="center"> 
	 * <td>Character<td>Double
	 * <tr ALIGN="center"> 
	 * <td>.<td>-1.0
	 * <tr ALIGN="center"> 
	 * <td>#<td>1.0
	 * </tr></tr>
	 * </table>
	 * 'qualquer outro' =  0</ul>
	 * @param file - arquivo a ser lido
	 */
	public LeituraArquivo(File file) {
		this(file, iniciarMapaDefault());
	}



	/**
	 * Constroi um leitor de arquivo, onde ele ira abri o arquivo
	 * e podera transformar em um vetor de double, sendo que
	 * cada {@link Character} do arquivo irá conter um valor
	 * @param file - arquivo a ser lido
	 * @param configuracoes - mapa de configuracoes, onde sera descrito o {@link Character} e seu valor em {@link Double},
	 * caso o {@link Character} não esteja mapeado o seu valor será igual a 0 (zero)
	 */
	public LeituraArquivo(File file, Map<Character, Double> configuracoes) {
		this(file, configuracoes, 0d);
	}


	/**
	 * Constroi um leitor de arquivo, onde ele ira abri o arquivo
	 * e podera transformar em um vetor de double, sendo que
	 * cada {@link Character} do arquivo irá conter um valor
	 * @param file - arquivo a ser lido
	 * @param configuracoes - mapa de configuracoes, onde sera descrito o {@link Character} e seu valor em {@link Double},
	 * caso o {@link Character} não esteja mapeado o seu valor será igual ao valor passado como parametro
	 * @param valorDesconhecido - valor para o caracter desconhecido
	 */
	public LeituraArquivo(File file, Map<Character, Double> configuracoes,double valorDesconhecido) {
		super();
		this.file = file;
		this.configuracoes = configuracoes;
		this.valorDesconhecido = valorDesconhecido;
	}



	private static Map<Character, Double> iniciarMapaDefault(){
		Map<Character, Double> mapa = new HashMap<Character, Double>();
		mapa.put('#', 1d);
		mapa.put('.', -1d);
		return mapa;
	}



	/**
	 * Transforma um arquivo em vetor de double
	 * @param linhas - linhas do arquivo
	 * @param colunas - colunas do arquivo
	 * @return um vetor de linha*colnas
	 */
	public double[] toArray(int linhas, int colunas){
		double [] array = new double [linhas * colunas];
		int cont = 0;
		try {
			BufferedReader reader = new BufferedReader(new FileReader(file));
			for (int i = 1; i <= linhas; i++) {
				String str = reader.readLine();
				for (int j = 0; j < colunas; j++) {
					Double x = configuracoes.get(str.charAt(j));
					if(x == null)
						x = valorDesconhecido;


					array[cont] = x;
					cont++;
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return array;
	}

	/**
	 * Transforma para String um vetor de double conforme as configuracoes descritas na classe atraves de um 
	 * {@link Map}, onde possui o {@link Character} e seu valor {@link Double} 
	 * @param valores - valores a serem transformados em String 
	 * @return {@link String} com a representação dos valores
	 */
	public String toString(double[] valores){
		String str = "";
		Map<Double, Character> temp = new HashMap<Double, Character>();
		List<Character> keys = new ArrayList<Character>(configuracoes.keySet());
		List<Double> values = new ArrayList<Double>(configuracoes.values());
		for (int i = 0; i < keys.size(); i++) {
			temp.put(values.get(i), keys.get(i));
		}
		for (int i = 0; i < valores.length; i++) {
			str += temp.get(valores[i]);
		}
		return str;
	}
	/**
	 * Transforma para String um vetor de double conforme as configuracoes descritas na classe atraves de um 
	 * {@link Map}, onde possui o {@link Character} e seu valor {@link Double}.
	 * @param valores - valores a serem transformados em String 
	 * @param quebraLinha - quebra a linha sepre que <code>i%quebraLinha == 0</code>
	 * @return {@link String} com a representação dos valores
	 */
	public String toString(double[] valores, int quebraLinha){
		String str = "";
		Map<Double, Character> temp = new HashMap<Double, Character>();
		List<Character> keys = new ArrayList<Character>(configuracoes.keySet());
		List<Double> values = new ArrayList<Double>(configuracoes.values());
		for (int i = 0; i < keys.size(); i++) {
			temp.put(values.get(i), keys.get(i));
		}
		for (int i = 0; i < valores.length; i++) {
			if(i%quebraLinha == 0)
				str+="\n";
			str += temp.get(valores[i]);
		}
		return str;
	}

	/**
	 * @return conteudo do arquivo
	 */
	public String toString() {
		String str = "";
		try {
			BufferedReader reader = new BufferedReader(new FileReader(file));
			String s;
			while ((s = reader.readLine()) != null) {
				str +=s+"\n";
			}
		} catch (IOException e) {
			System.err.println("Problemas com o Arquivo");
		}
		return str;
	}

	public File getFile() {
		return file;
	}

	public void setFile(File file) {
		this.file = file;
	}


}
